package org.example.netty.springBoot;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;

/**
 * Netty 服务器
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2021/8/9 14:46
 */
@SuppressWarnings("all")
public class NettyServer {
    private static final Logger log = LoggerFactory.getLogger(NettyServer.class);
    private static final String SERVER_IP = "127.0.0.1";
    private static final int SERVER_PORT = 9308;

    public void start() {
        //网络套接字地址（IP地址+端口号）
        InetSocketAddress socketAddress = new InetSocketAddress(SERVER_IP, SERVER_PORT);
        //主线程组：用于服务端接受客户端连接，指定线程数，0 表示默认值.
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        //工作线程组：用于进行 SocketChannel 网络读写
        EventLoopGroup workGroup = new NioEventLoopGroup(200);
        //ServerBootstrap 是 Netty 用于启动 NIO 服务端的辅助启动类，用于降低开发难度
        ServerBootstrap bootstrap = new ServerBootstrap();
        try {
            bootstrap.group(bossGroup, workGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ServerChannelInitializer())
                    .localAddress(socketAddress)
                    .option(ChannelOption.SO_BACKLOG, 1024)//设置队列大小
                    // 两小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            //绑定端口,开始接收进来的连接
            ChannelFuture future = bootstrap.bind(socketAddress).sync();
            log.info("服务器启动开始监听端口: {}", socketAddress);
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("服务器开启失败", e);
        } finally {
            bossGroup.shutdownGracefully();//优雅退出，释放线程池资源, 关闭主线程组
            workGroup.shutdownGracefully();//优雅退出，释放线程池资源, 关闭工作线程组
        }
    }

    /**
     * Netty 服务初始化器
     */
    private class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {
            //添加编解码、处理器
            socketChannel.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
            socketChannel.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
            socketChannel.pipeline().addLast(new NettyServerHandler());
        }
    }
}
